package top.ffhome.common.core.mybatisplus.service.impl;

import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.extension.toolkit.SqlHelper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import top.ffhome.common.core.domain.scope.Field;
import top.ffhome.common.core.domain.scope.LocalDataScope;
import top.ffhome.common.core.mybatisplus.mapper.BaseMapper;
import top.ffhome.common.core.mybatisplus.service.IBaseService;
import top.ffhome.common.utils.SecurityUtils;
import top.ffhome.common.utils.spring.SpringUtils;

import java.io.Serializable;
import java.util.Collection;
import java.util.List;
import java.util.function.Consumer;

public class BaseServiceImpl<M extends BaseMapper<T>, T> implements IBaseService<T> {
    /**
     * 数据权限过滤关键字
     */
    public static final String DATA_SCOPE = "dataScope";

    protected Logger log = LoggerFactory.getLogger(getClass());

    @Autowired
    protected M mapper;

    protected QueryWrapper<T> generateWrapper(T query) {
        return new QueryWrapper<T>().select("*");
    }

    @Override
    @Transactional
    public boolean insert(T entity) {
        beforeInsert(entity);
        boolean ret = SqlHelper.retBool(mapper.insert(entity));
        afterInsert(entity);
        return ret;
    }

    /**
     * 新增前置功能，如需中止新增可抛出异常，自动增加创建者及时间
     *
     * @param entity
     */
    protected void beforeInsert(T entity) {
        beforeSave(entity);
    }

    /**
     * 新增后置功能
     *
     * @param entity
     */
    protected void afterInsert(T entity) {
        afterSave(entity);
        SpringUtils.getAopProxy(this).clearCache();
    }

    @Override
    @Transactional
    public boolean updateById(T entity) {
        beforeUpdate(entity);
        boolean ret = SqlHelper.retBool(mapper.updateById(entity));
        afterUpdate(entity);
        return ret;
    }

    /**
     * 修改前置功能，如需重载此方法，需先调用父类此方法，或需单独调用检查乐观锁函数
     *
     * @param entity
     */
    protected void beforeUpdate(T entity) {
        beforeSave(entity);
    }

    /**
     * 修改后置功能
     *
     * @param entity
     */
    protected void afterUpdate(T entity) {
        afterSave(entity);
        SpringUtils.getAopProxy(this).clearCache();
    }

    /**
     * 保存前置功能<br/>
     * 如果重载了preInsert，而没有调用父类方法，则新增时此方法无效<br/>
     * 如果重载了preUpdate，而没有调用父类方法，则修改时此方法无效<br/>
     *
     * @param entity
     */
    protected void beforeSave(T entity) {
    }

    /**
     * 保存后置功能<br/>
     * 如果重载了afterInsert，而没有调用父类方法，则新增时此方法无效<br/>
     * 如果重载了afterUpdate，而没有调用父类方法，则修改时此方法无效<br/>
     *
     * @param entity
     */
    protected void afterSave(T entity) {
    }

    @Override
    @Transactional
    public boolean deleteById(Serializable id) {
        beforeDelete(id);
        boolean ret = SqlHelper.retBool(mapper.deleteById(id));
        afterDelete(id);
        return ret;
    }

    @Override
    @Transactional
    public boolean deleteByIds(Collection<? extends Serializable> idList) {
        if (CollectionUtils.isEmpty(idList)) {
            return false;
        }
        beforeDelete(idList);
        boolean ret = SqlHelper.retBool(mapper.deleteBatchIds(idList));
        afterDelete(idList);
        return ret;
    }

    @Override
    public boolean delete(Wrapper<T> queryWrapper) {
        return SqlHelper.retBool(mapper.delete(queryWrapper));
    }

    /**
     * 删除前置功能
     *
     * @param id
     */
    protected void beforeDelete(Serializable id) {
    }

    /**
     * 删除后置功能
     *
     * @param id
     */
    protected void afterDelete(Serializable id) {
        SpringUtils.getAopProxy(this).clearCache();
    }

    /**
     * 删除前置功能
     *
     * @param ids
     */
    protected void beforeDelete(Collection<? extends Serializable> ids) {
    }

    /**
     * 删除后置功能
     *
     * @param ids
     */
    protected void afterDelete(Collection<? extends Serializable> ids) {
        SpringUtils.getAopProxy(this).clearCache();
    }

    /**
     * 取得对象
     * 可通过注解将对象进行缓存
     * 如：@Cacheable(value = "getOne")
     *
     * @param id
     * @return
     */
    @Override
    public T selectById(Serializable id) {
        beforeGet(id);
        T obj = mapper.selectById(id);
        afterGet(obj);
        return obj;
    }

    /**
     * 取得对象前置功能
     *
     * @param id
     */
    protected void beforeGet(Serializable id) {
    }

    /**
     * 取得对象后置功能
     *
     * @param entity
     */
    protected void afterGet(T entity) {
    }

    @Override
    public T selectOne(Wrapper<T> queryWrapper) {
        return mapper.selectOne(queryWrapper);
    }

    @Override
    public List<T> selectList(T query) {
        QueryWrapper<T> wrapper = generateWrapper(query);
        buildScopesWrapper(wrapper);
        return mapper.selectList(wrapper);
    }

    protected void buildScopesWrapper(QueryWrapper<T> wrapper) {
        List<Field> scopes = LocalDataScope.get();
        if (scopes != null) {
            log.debug("user id: {}, authority scope: {}", SecurityUtils.getLoginUser().getUserId(), scopes);
            wrapper.and(wp -> {
                for (Field field : scopes) {
                    if ("eq".equalsIgnoreCase(field.getMethod())) {
                        wp.or().eq(field.getField(), field.getValue());
                    } else if ("in".equalsIgnoreCase(field.getMethod())) {
                        wp.or().inSql(field.getField(), field.getValue());
                    }
                }
            });
        }
    }

    protected void buildScopesParams(Consumer<String> consumer) {
        StringBuilder sb = new StringBuilder();
        List<Field> scopes = LocalDataScope.get();
        log.debug("user id: {}, authority scope: {}", SecurityUtils.getLoginUser().getUserId(), scopes);
        if (scopes != null) {
            for (Field field : scopes) {
                if ("eq".equalsIgnoreCase(field.getMethod())) {
                    sb.append(" OR ").append(field.getField()).append(" ").append(field.getMethod()).append(" ").append(field.getValue());
                } else if ("in".equalsIgnoreCase(field.getMethod())) {
                    sb.append(" OR ").append(field.getField()).append(" ").append(field.getMethod()).append(" (").append(field.getValue()).append(")");
                }
            }
            if (sb.length() > 0) {
                consumer.accept(" AND (" + sb.toString().substring(4) + ")");
            }
        }
    }

    @Override
    public List<T> selectList(Wrapper<T> queryWrapper) {
        if (queryWrapper instanceof QueryWrapper) {
            buildScopesWrapper((QueryWrapper) queryWrapper);
        }
        return mapper.selectList(queryWrapper);
    }


    /**
     * 清除缓存
     * 此处通过注解清除缓存
     * 如：@CacheEvict(value = {"getOne", "getAllList"}, allEntries = true)
     * 可将指定的缓存清除，如： @Cacheable(value = "getAllList", unless = "#result == null || #result.size() == 0")
     */
    @Override
    public void clearCache() {
    }
}